Ext.ux.DirectedGraphPanel = Ext.extend(Ext.Panel, {
//	graphLayout: 'force-directed',
	entropyThrottle: false,
	nodes: {},
	graphLayoutConfig: {
		model: function(dataNode) {
			return {
				mass: 5
			}
		},
		
		view: function(dataNode, modelNode) {
			var nodeElement = document.createElement('div');
			Ext.fly(nodeElement).addClass('x-unselectable');
			nodeElement.style.position = 'absolute';
			nodeElement.id = "container-"+dataNode.uid;
			nodeElement.style.fontSize = dataNode.fontSize || "";
			nodeElement.innerHTML = dataNode.text;
//			nodeElement.onmousedown =  new EventHandler( this.graphLayout, this.graphLayout.handleMouseDownEvent, modelNode.id )
			return nodeElement
		}
	},
	
	edgeBuilder: function(dataNodeSource, destination) {
		if (this.svg) {
			return {
				'stroke': dataNodeSource.color,
				'stroke-width': '3px',
				'stroke-dasharray': 'none'
			}
		}
		else {
			return {
				'pixelColor': dataNodeSource.color,
				'pixelWidth': '2px',
				'pixelHeight': '1px',
				'pixels': 20
			}
		}
	},
	
	springConfig: {
		springConstant: 0.2,
		dampingConstant: 0.2,
		restLength: 70
	},
	
	magnetConfig: {
		magnetConstant: -4000,
		minimumDistance: 100
	},
	
//	getLayoutConstructor: function() {
//		switch(this.graphLayout) {
//			case 'force-directed':
//				return ForceDirectedLayout;
//		}
//	},
	
	onRender: function(ct, position) {
		if (!this.el) {
			Ext.ux.DirectedGraphPanel.superclass.onRender.call(this, ct, position);
			var graphContainer = new Ext.Element(document.createElement('div'));
			graphContainer.addClass('x-graph-container');
			this.body.appendChild(graphContainer);
			
//			this.graphLayout = new (this.getLayoutConstructor())(graphContainer.dom, true);
			this.graphLayout = new ForceDirectedLayout(graphContainer.dom, true);
			
			this.graphLayout.config._default = this.graphLayoutConfig;
			
			var that = this;
			
			Ext.apply(this.graphLayout, {
				forces: {
					spring: {
						_default: function(nodeA, nodeB, isParentChild) {
							return that.springConfig;
						}
					},
					
					magnet: function(){
						return that.magnetConfig;
					}
				}
			});
			
			this.graphLayout.viewEdgeBuilder = this.edgeBuilder;
			this.graphLayout.model.ENTROPY_THROTTLE = this.entropyThrottle;

			this.addNode({
				color: "#ffcccc",
				text: "<center>Select resources from panel on left:<br />See a force-directed graph of their relationships</center>"
			});
			
			this.initTimer();
		}
	},
	
	clear: function(){
		this.nodes = {};
		this.graphLayout.clear();
	},
	
	addNode: function(config){
		var node = new DataGraphNode();
		Ext.apply(node, config);
		this.nodes[config.uid] = node;
		this.graphLayout.newDataGraphNode(node);
	},
	
	addEdge: function(origin, conclusion) {
		origin = this.nodes[origin.id];
		conclusion = this.nodes[conclusion.id];
		if (origin && conclusion) {
			this.graphLayout.newDataGraphEdge(origin, conclusion);
		}
	},
	
	addRelationship: function(resource, relationship) {
		var related = this.nodes[relationship.related.id];
		var _resource = this.nodes[resource.id];
		var _relationship = this.nodes[relationship.id];
		if(related && _resource && _relationship) {
			views.graph.addEdge(resource, relationship);
			views.graph.addEdge(relationship.related, relationship);
		}
	},
	
	initTimer: function() {
		this.timer = new Timer(0);
		this.timer.subscribe(this.graphLayout);
		this.timer.start();
	}
});

new Ext.ux.MVC({
	name: "viewer",
	config: {
		site: "//localhost:3000"
	},
	
	models: {
		resources: ['data.JsonStore', {
			url: '/resources.json',
			autoLoad: true,
			root: 'resources',
			fields: [
				'name',
				'relationships',
				'columns'
			]
		}]
	},
	
	views: {
		list: ['grid.GridPanel', {
			region: 'west',
			split: true,
			width: 200,
			minWidth: 200,
			collapsible: true,
			layout: 'fit',
			title: 'Resource List',
			selModel: new Ext.grid.CheckboxSelectionModel({sortable:true}),
			viewConfig: {
				forceFit: true
			},
			columns: [
				new Ext.grid.CheckboxSelectionModel({sortable:true}),
				{header: "Resource", dataIndex: 'name', resizable: false}
			],
			ds: new Ext.data.Store(),
			stripeRows: true
		}],
		
		graph: ['ux.DirectedGraphPanel', {
			region:'center',
			title: 'Graph Viewer'
		}]
	},
	
	controllers: function(){	var views = viewer.views, models = viewer.models; return {
		viewport: {
			'render': function(viewport) {
				viewport.add(views.graph, views.list);
			}
		},
		
		resources: {
			'load': function(resources, records, options) {
				resources.each(function(resource){
					resource.id = Ext.id();
					Ext.each(resource.data.relationships,
						function(relationship){
							relationship.id = Ext.id();
							relationship.related = resources.getAt(resources.find('name', relationship.related));	
						});
				});
			}
		},
		
		list: {
			'render': function(list) {
				list.reconfigure(models.resources, list.colModel);
			},
			
			'selModel:selectionchange': function(sm) {
				views.graph.clear();
				var resources = sm.getSelections();
				Ext.each(resources,
					function(resource) {
						views.graph.addNode({
							color: '#ffcccc',
							text: resource.data.name,
							uid: resource.id,
							fontSize: '20px'
						});
						Ext.each(resource.data.relationships,
							function(relationship) {
								if (resources.indexOf(relationship.related) !== -1) {
									views.graph.addNode({
										color: 'ffccff',
										text: resource.data.name +" "+ relationship.macro +" "+ relationship.related.data.name,
										uid: relationship.id,
										fontSize: '10px'
									});
								}
							});
					});
				
				Ext.each(resources,
					function(resource){
						Ext.each(resource.data.relationships,
							function(relationship) {
								views.graph.addRelationship(resource, relationship);
							});
					});
			}
		}
	}}
});